package edu.uestc.gene.model;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import edu.uestc.gene.entity.AdverseDrugReaction;
import edu.uestc.gene.entity.DataCollector;
import edu.uestc.gene.entity.Drug;
import edu.uestc.gene.entity.Gene;
import edu.uestc.gene.entity.RelationshipTable;

public class Statistics {

	private static Statistics statistics;

	public static int GENES_NUM, ADRS_NUM, DRUGS_NUM, ROUND_SCALE = 10;

	private List<Drug> drugs;// 所有药物
	private List<Gene> genes;// 所有基因
	private List<AdverseDrugReaction> adrs;// 所有副作用

	// 为节省内存将药物，基因，副作用以序号进行编码再存储
	private Map<String, Integer> drugs_encode;
	private Map<String, Integer> genes_encode;
	private Map<String, Integer> adrs_encode;

	private RelationshipTable relationshipTable;// 全局药物表

	public static Statistics getInstance() {
		if (statistics == null) {
			statistics = new Statistics();
		}
		return statistics;
	}

	private Statistics() {
	}

	private DataCollector readDataCollector() {
		FileInputStream fis = null;
		ObjectInputStream ois = null;
		DataCollector object = null;
		File f = new File(DataCollector.BADDFILENAME);
		try {
			fis = new FileInputStream(f);
			ois = new ObjectInputStream(new BufferedInputStream(fis));
			object = (DataCollector) ois.readObject();
		} catch (FileNotFoundException e) {
			System.err.println("BADD文件不存在!\n" + e);
			return null;
		} catch (IOException e) {
			System.err.println("文件读取错误!\n" + e);
			return null;
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
			return null;
		} finally {
			try {
				ois.close();
				fis.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return object;
	}

	/**
	 * 读取数据文件到内存，并初始化各个变量
	 */
	public void initData(boolean needCombine) {
		DataCollector collector = readDataCollector();
		if (collector == null) {
			return;
		}
		collector.init(needCombine);
		drugs = collector.getDrugs();
		genes = collector.getGenes();
		adrs = collector.getAdrs();
		GENES_NUM = genes.size();
		ADRS_NUM = adrs.size();
		DRUGS_NUM = drugs.size();
		encode();
		relationshipTable = RelationshipTable.getInstance();
	}

	public void index() {
		for (int i = 0; i < DRUGS_NUM; i++) {
			Drug currentDrug = drugs.get(i);
			List<AdverseDrugReaction> correspondADR = currentDrug
					.getDrug_adrs();
			List<Gene> correspondGene = currentDrug.getDrug_genes();
			for (int j = 0; j < correspondGene.size(); j++) {
				int x_gene = genes_encode.get(correspondGene.get(j).getName());
				for (int k = 0; k < correspondADR.size(); k++) {
					int y_adr = adrs_encode.get(correspondADR.get(k).getName());
					relationshipTable.addRelationship(x_gene, y_adr,
							drugs_encode.get(currentDrug.getName()));
				}
			}
		}
		// 全局关系表构建完成
		relationshipTable.index();
	}

	public double getProbByGeneAndADR(Gene gene, AdverseDrugReaction adr) {
		return relationshipTable.getProbabilityOfGeneByADR(
				genes_encode.get(gene.getName()),
				adrs_encode.get(adr.getName()));
	}

	public double getProbByGenesAndADR(List<Gene> genes, AdverseDrugReaction adr) {
		if (genes.size() == 1) {
			return relationshipTable.getProbabilityOfGeneByADR(
					genes_encode.get(genes.get(0).getName()),
					adrs_encode.get(adr.getName()));
		}
		int[] codes = new int[genes.size()];
		for (int i = 0; i < genes.size(); i++) {
			codes[i] = genes_encode.get(genes.get(i).getName());
		}
		return relationshipTable.getProbabilityOfGenesByADR(codes,
				adrs_encode.get(adr.getName()));
	}

	private void encode() {
		drugs_encode = new HashMap<String, Integer>(DRUGS_NUM);
		for (int i = 0; i < DRUGS_NUM; i++) {
			drugs_encode.put(drugs.get(i).getName(), i);
		}
		genes_encode = new HashMap<String, Integer>(GENES_NUM);
		for (int i = 0; i < GENES_NUM; i++) {
			genes_encode.put(genes.get(i).getName(), i);
		}
		adrs_encode = new HashMap<String, Integer>(ADRS_NUM);
		for (int i = 0; i < ADRS_NUM; i++) {
			adrs_encode.put(adrs.get(i).getName(), i);
		}
	}

	public boolean match() {
		long a = relationshipTable.getAll();
		long b = 0L;
		for (int i = 0; i < drugs.size(); i++) {
			b += (drugs.get(i).getDrug_adrs().size() * drugs.get(i)
					.getDrug_genes().size());
		}
		return a == b;
	}

	public List<Drug> getDrugs() {
		return drugs;
	}

	public List<Gene> getGenes() {
		return genes;
	}

	public List<AdverseDrugReaction> getAdrs() {
		return adrs;
	}

	public Map<String, Integer> getDrugs_encode() {
		return drugs_encode;
	}

	public Map<String, Integer> getGenes_encode() {
		return genes_encode;
	}

	public Map<String, Integer> getAdrs_encode() {
		return adrs_encode;
	}

	public static void main(String[] args) {
		Statistics statistics = Statistics.getInstance();
		statistics.initData(false);
		statistics.index();
		List<Gene> allgene = statistics.getGenes();
		List<AdverseDrugReaction> alladr = statistics.getAdrs();
		Map<String, Integer> map = statistics.getGenes_encode();
		String fileName = "F:\\电子科大\\论文\\生物计算\\基因副作用匹配\\打包\\测试数据\\1.txt";
		String fileContent = Tool.readFile(fileName);
		List<Gene> genes = new ArrayList<Gene>();

		String[] geneContent = fileContent.split(",");
		int count = 0;
		for (int i = 0; i < geneContent.length; i++) {
			if ("".equals(geneContent[i].trim())) {
				continue;
			}
			count++;
			Gene gene = allgene.get(map.get(geneContent[i].trim()));
			genes.add(gene);
		}
		BigDecimal allprob = new BigDecimal(0);
		for (int i = 0; i < alladr.size(); i++) {
			allprob = allprob.add(new BigDecimal(statistics
					.getProbByGenesAndADR(genes, alladr.get(i))));
		}
		System.out.println(allprob.doubleValue());
		System.out.println(statistics.match());
		// List<AdverseDrugReaction> adrs = statistics.getAdrs();
		// ExecutorService service = Executors.newFixedThreadPool(4);
		// for (int i = 0; i < adrs.size(); i++) {
		// service.execute(new AnalyzeThread(statistics, adrs.get(i)));
		// }
	}
}